package org.ruoyi.knowledge.service.impl;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.InputStreamResource;
import org.springframework.web.util.UriComponentsBuilder;
import org.ruoyi.knowledge.service.RagflowService;

import java.util.*;
import java.io.IOException;

/**
 * Ragflow服务实现类
 * 
 * @author Lion Li
 * @date 2024-10-23
 */
@Service
public class RagflowServiceImpl implements RagflowService {

    @Value("${chat.api.host:http://192.168.0.150:7777/api/v1}")
    private String ragflowBaseUrl;
    
    @Value("${chat.api.key:ragflow-liZDlhNjIwYTViMzExZjBiNTE1MjY1ZW}")
    private String apiKey;
    
    private static final List<String> ALLOWED_EXTENSIONS = Arrays.asList("pdf", "txt", "docx", "pptx", "xlsx", "xls", "csv", "json");
    private static final int MAX_RETRIES = 3;

    private final RestTemplate restTemplate = new RestTemplate();

    @Override
    public String createDataset(String datasetName) {
        // 使用默认配置
        Map<String, Object> defaultConfig = new HashMap<>();
        defaultConfig.put("chunk_token_num", 400);
        defaultConfig.put("delimiter", "\n\n\n");
        defaultConfig.put("html4excel", false);
        defaultConfig.put("layout_recognize", "DeepDOC");
        defaultConfig.put("raptor", Map.of("use_raptor", false));
        
        // 传递null使用RAGFlow服务器默认的embedding模型
        return createDataset(datasetName, null, "naive", defaultConfig, "me");
    }

    @Override
    public String createDataset(String datasetName, String embeddingModel, String chunkMethod, Map<String, Object> parserConfig, String permission) {
        String url = ragflowBaseUrl + "/datasets";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + apiKey);

        Map<String, Object> body = new HashMap<>();
        body.put("name", datasetName);
        // 只有当明确指定了embedding_model时才添加，否则使用RAGFlow服务器的默认配置
        if (embeddingModel != null && !embeddingModel.trim().isEmpty()) {
            body.put("embedding_model", embeddingModel);
        }
        body.put("permission", permission != null ? permission : "me");
        body.put("chunk_method", chunkMethod != null ? chunkMethod : "naive");
        
        // 使用前端传入的配置（只包含前端实际输入的字段）
        if (parserConfig != null && !parserConfig.isEmpty()) {
            body.put("parser_config", parserConfig);
        }
        // 如果parserConfig为空，则不添加parser_config字段，让RAGFlow使用服务器默认配置

        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);

        try {
            System.out.println("创建RAGFlow数据集，配置: " + body);
            ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);
            
            System.out.println("RAGFlow响应状态码: " + response.getStatusCode());
            System.out.println("RAGFlow响应内容: " + response.getBody());
            
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                
                // 检查是否有code字段
                Integer code = (Integer) responseBody.get("code");
                if (code != null && code != 0) {
                    String msg = (String) responseBody.get("msg");
                    System.err.println("RAGFlow返回错误: code=" + code + ", msg=" + msg);
                    return null;
                }
                
                // 获取data字段
                Object dataObj = responseBody.get("data");
                if (dataObj instanceof Map) {
                    Map<String, Object> data = (Map<String, Object>) dataObj;
                    String datasetId = (String) data.get("id");
                    System.out.println("创建数据集成功，ID: " + datasetId);
                    return datasetId;
                } else {
                    System.err.println("RAGFlow返回的data字段格式不正确: " + dataObj);
                }
            } else {
                System.err.println("RAGFlow响应失败: status=" + response.getStatusCode() + ", body=" + response.getBody());
            }
        } catch (Exception e) {
            System.err.println("创建数据集失败: " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String getDatasetIdByName(String name) {
        String url = ragflowBaseUrl + "/datasets";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            System.out.println("查找数据集: " + name);
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                List<Map<String, Object>> dataList = (List<Map<String, Object>>) response.getBody().get("data");
                if (dataList != null) {
                    System.out.println("找到 " + dataList.size() + " 个数据集");
                    for (Map<String, Object> data : dataList) {
                        String datasetName = (String) data.get("name");
                        System.out.println("数据集名称: '" + datasetName + "', 查找名称: '" + name + "'");
                        if (name.equals(datasetName)) {
                            System.out.println("数据集已存在，ID: " + data.get("id"));
                            return (String) data.get("id");
                        }
                    }
                    System.out.println("未找到匹配的数据集");
                }
            }
        } catch (Exception e) {
            System.err.println("查找数据集失败: " + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<String> uploadDocument(String datasetId, MultipartFile file) {
        return uploadDocuments(datasetId, List.of(file));
    }

    @Override
    public List<String> uploadDocuments(String datasetId, List<MultipartFile> files) {
        List<String> uploadedDocumentIds = new ArrayList<>();
        
        for (MultipartFile file : files) {
            if (file != null && !file.isEmpty() && isAllowedFile(file)) {
                boolean success = false;
                int attempt = 0;
                while (!success && attempt < MAX_RETRIES) {
                    attempt++;
                    try {
                        String url = ragflowBaseUrl + "/datasets/" + datasetId + "/documents";
                        HttpHeaders headers = new HttpHeaders();
                        headers.set("Authorization", "Bearer " + apiKey);
                        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

                        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
                        try {
                            body.add("file", new MultipartFileResource(file));
                        } catch (IOException e) {
                            System.err.println("创建文件资源失败: " + file.getOriginalFilename());
                            continue;
                        }

                        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
                        ResponseEntity<Map> response = restTemplate.postForEntity(url, requestEntity, Map.class);

                        if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                            List<Map<String, Object>> dataList = (List<Map<String, Object>>) response.getBody().get("data");
                            if (dataList != null && !dataList.isEmpty()) {
                                String documentId = (String) dataList.get(0).get("id");
                                uploadedDocumentIds.add(documentId);
                                System.out.println("上传成功: " + file.getOriginalFilename() + "，document_id: " + documentId);
                                success = true;
                            }
                        }
                    } catch (Exception e) {
                        System.err.println("上传失败: " + file.getOriginalFilename() + "，重试 " + attempt + "/" + MAX_RETRIES);
                        if (attempt == MAX_RETRIES) e.printStackTrace();
                    }
                }
            }
        }
        return uploadedDocumentIds;
    }

    @Override
    public boolean parseDocuments(String datasetId, List<String> documentIds) {
        if (documentIds.isEmpty()) return false;

        String url = ragflowBaseUrl + "/datasets/" + datasetId + "/chunks";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + apiKey);

        Map<String, Object> body = new HashMap<>();
        body.put("document_ids", documentIds);

        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);

        try {
            ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                Integer code = (Integer) response.getBody().get("code");
                if (code != null && code == 0) {
                    System.out.println("文档解析成功，生成向量。");
                    return true;
                } else {
                    System.err.println("文档解析失败: " + response.getBody());
                }
            }
        } catch (Exception e) {
            System.err.println("调用解析接口失败");
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean deleteDataset(String datasetId) {
        String url = ragflowBaseUrl + "/datasets/" + datasetId;
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            System.out.println("准备删除RAGFlow数据集，URL: " + url);
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.DELETE, entity, Map.class);
            
            HttpStatusCode statusCode = response.getStatusCode();
            int statusValue = statusCode.value();
            System.out.println("删除数据集响应状态码: " + statusValue);
            
            Map body = response.getBody();
            if (body != null) {
                System.out.println("删除数据集响应内容: " + body);
            }
            
            // 检查响应状态（DELETE通常返回200或204）
            boolean success = statusValue == 200 || statusValue == 204;
            if (success) {
                System.out.println("成功删除RAGFlow数据集: " + datasetId);
            } else {
                System.out.println("删除RAGFlow数据集失败，状态码: " + statusValue);
            }
            return success;
        } catch (Exception e) {
            System.err.println("删除数据集失败: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean isServiceAvailable() {
        try {
            String url = ragflowBaseUrl + "/datasets";
            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization", "Bearer " + apiKey);
            HttpEntity<Void> entity = new HttpEntity<>(headers);
            
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
            return response.getStatusCode().value() == 200;
        } catch (Exception e) {
            return false;
        }
    }

    private boolean isAllowedFile(MultipartFile file) {
        String name = file.getOriginalFilename();
        if (name == null) return false;
        String lowerName = name.toLowerCase();
        return ALLOWED_EXTENSIONS.stream().anyMatch(lowerName::endsWith);
    }
    
    @Override
    public List<Map<String, Object>> getAllDatasets() {
        String url = ragflowBaseUrl + "/datasets";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                List<Map<String, Object>> dataList = (List<Map<String, Object>>) response.getBody().get("data");
                if (dataList != null) {
                    System.out.println("获取到 " + dataList.size() + " 个数据集");
                    return dataList;
                }
            }
        } catch (Exception e) {
            System.err.println("获取数据集列表失败: " + e.getMessage());
            e.printStackTrace();
        }
        return new ArrayList<>();
    }
    
    @Override
    public boolean deleteDocument(String datasetId, String documentId) {
        String url = ragflowBaseUrl + "/datasets/" + datasetId + "/documents/" + documentId;
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.DELETE, entity, Map.class);
            return response.getStatusCode().value() == 200;
        } catch (Exception e) {
            System.err.println("删除文档失败: " + e.getMessage());
            return false;
        }
    }

    @Override
    public List<Map<String, Object>> getDocuments(String datasetId) {
        String url = ragflowBaseUrl + "/datasets/" + datasetId + "/documents";
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);
            
            System.out.println("RAGFlow获取文档列表响应: " + response.getBody());
            
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                Object dataObj = response.getBody().get("data");
                
                if (dataObj instanceof Map) {
                    Map<String, Object> dataMap = (Map<String, Object>) dataObj;
                    Object docsObj = dataMap.get("docs");
                    
                    if (docsObj instanceof List) {
                        List<Map<String, Object>> docList = (List<Map<String, Object>>) docsObj;
                        System.out.println("找到 " + docList.size() + " 个文档");
                        return docList;
                    } else {
                        System.err.println("docs字段不是List类型: " + (docsObj != null ? docsObj.getClass() : "null"));
                    }
                } else if (dataObj instanceof List) {
                    List<Map<String, Object>> dataList = (List<Map<String, Object>>) dataObj;
                    System.out.println("找到 " + dataList.size() + " 个文档（直接List格式）");
                    return dataList;
                } else {
                    System.err.println("响应data字段不是预期类型: " + (dataObj != null ? dataObj.getClass() : "null"));
                    System.err.println("响应内容: " + response.getBody());
                }
            }
        } catch (Exception e) {
            System.err.println("获取文档列表失败: " + e.getMessage());
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    @Override
    public boolean updateDataset(String datasetId, Map<String, Object> updateData) {
        String url = ragflowBaseUrl + "/datasets/" + datasetId;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(updateData, headers);

        try {
            System.out.println("更新RAGFlow数据集，URL: " + url);
            System.out.println("更新数据: " + updateData);
            
            // 尝试使用 PUT 方法（RAGFlow不支持PATCH）
            ResponseEntity<Map> response = restTemplate.exchange(url, HttpMethod.PUT, entity, Map.class);
            
            int statusCode = response.getStatusCode().value();
            System.out.println("响应状态码: " + statusCode);
            System.out.println("响应内容: " + response.getBody());
            
            boolean success = statusCode == 200;
            if (success) {
                System.out.println("✓✓✓ 成功更新RAGFlow数据集配置");
            } else {
                System.err.println("✗✗✗ 更新数据集失败，状态码: " + statusCode);
            }
            return success;
        } catch (Exception e) {
            System.err.println("❌ 更新数据集异常: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Map<String, Object> getDocument(String datasetId, String documentId) {
        String url = ragflowBaseUrl + "/datasets/" + datasetId + "/documents/" + documentId;
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            // 先尝试获取String响应
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
            if (response.getStatusCode().value() == 200 && response.getBody() != null) {
                String body = response.getBody();
                System.out.println("文档详情响应: " + body);
                
                if (body.startsWith("{")) {
                    // 是JSON，手动解析
                    // 这里简化处理，直接返回空
                    return new HashMap<>();
                }
            }
        } catch (Exception e) {
            System.err.println("获取文档信息失败: " + e.getMessage());
            e.printStackTrace();
        }
        return new HashMap<>();
    }

    @Override
    public Map<String, Object> getDocumentChunks(String datasetId, String documentId, int pageNum, int pageSize) {
        // 使用正确的 RAGFlow API 路径
        // 从 ragflowBaseUrl (如 http://192.168.0.150:7777/api/v1) 中去掉 /api/v1
        // 去掉 /api/v1 或 /api/v1/ 后缀
        String baseUrl = ragflowBaseUrl.replaceAll("/api/v1/?$", "");
        
        // 再确保去掉末尾的斜杠
        if (baseUrl.endsWith("/")) {
            baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
        }
        
        System.out.println("原始URL: " + ragflowBaseUrl);
        System.out.println("处理后URL: " + baseUrl);
        
        // 使用不带/api/v1的路径，因为chunk API不在api/v1下
        String url = baseUrl + "/chunk/parsed/chunks";
        System.out.println("尝试API路径: " + url);
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + apiKey);
        
        // 添加查询参数
        UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
                .queryParam("id", documentId)
                .queryParam("doc_id", documentId)
                .queryParam("page_num", pageNum)
                .queryParam("page_size", pageSize);
        
        String fullUrl = builder.toUriString();
        HttpEntity<Void> entity = new HttpEntity<>(headers);

        try {
            System.out.println("获取文档chunks，URL: " + fullUrl);
            
            ResponseEntity<String> response = restTemplate.exchange(fullUrl, HttpMethod.GET, entity, String.class);
            System.out.println("响应状态码: " + response.getStatusCode().value());
            System.out.println("响应头: " + response.getHeaders());
            
            String body = response.getBody();
            if (body != null) {
                System.out.println("响应体前500字符: " + body.substring(0, Math.min(500, body.length())));
                
                // 如果返回JSON响应
                if (body.startsWith("{") && body.contains("\"code\":")) {
                    System.out.println("✓ 收到RAGFlow响应");
                    
                    // 检查是否有错误
                    if (body.contains("\"code\":100")) {
                        System.err.println("✗ RAGFlow返回错误: " + body);
                        // 如果是认证错误，尝试不带Authorization
                        if (body.contains("authorized")) {
                            System.out.println("尝试不使用Authorization...");
                            HttpHeaders noAuthHeaders = new HttpHeaders();
                            ResponseEntity<String> retryResponse = restTemplate.exchange(fullUrl, HttpMethod.GET, new HttpEntity<>(noAuthHeaders), String.class);
                            String retryBody = retryResponse.getBody();
                            System.out.println("重试响应: " + retryBody);
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("获取文档chunks失败: " + e.getMessage());
            e.printStackTrace();
        }
        return new HashMap<>();
    }

    @Override
    public boolean syncKnowledgeToRagflow(String kid) {
        // 这个方法需要在KnowledgeInfoService中实现
        // 因为需要访问KnowledgeAttachMapper
        return false;
    }

    @Override
    public boolean batchDeleteDocuments(String datasetId, List<String> documentIds) {
        if (documentIds == null || documentIds.isEmpty()) {
            return true;
        }
        
        boolean allSuccess = true;
        for (String documentId : documentIds) {
            if (!deleteDocument(datasetId, documentId)) {
                allSuccess = false;
                System.err.println("删除文档失败: " + documentId);
            }
        }
        return allSuccess;
    }

    /**
     * MultipartFile资源适配器
     */
    private static class MultipartFileResource extends InputStreamResource {
        private final MultipartFile multipartFile;
        
        public MultipartFileResource(MultipartFile multipartFile) throws IOException {
            super(multipartFile.getInputStream());
            this.multipartFile = multipartFile;
        }
        
        @Override
        public String getFilename() {
            return multipartFile.getOriginalFilename();
        }
        
        @Override
        public long contentLength() {
            return multipartFile.getSize();
        }
    }
}
